#include "ShareMem.hpp"
#include <cstring>
#include <fcntl.h>
#include <format>
#include <stdexcept>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>

ShareMem::ShareMem(const std::string &name, long size)
    : len(size + sizeof(int64_t)) {
  memname = std::format("/SUPERMATRIX_REALTIME_IMAGE_MEM_{}", name);
  semname = std::format("/SUPERMATRIX_REALTIME_IMAGE_SEM_{}", name);
  sem = sem_open(semname.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR, 1);
  if (sem == nullptr)
    throw std::runtime_error("Can't create semaphore");
  memfd = shm_open(memname.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
  if (memfd == -1)
    throw std::runtime_error("Can't create memfd");
  if (ftruncate(memfd, len) == -1)
    throw std::runtime_error(
        std::format("Can't set sharemem name = {} size = {}", name, len));
  memaddr = (unsigned char *)mmap(nullptr, len, PROT_READ | PROT_WRITE,
                                  MAP_SHARED, memfd, 0);
  if (memaddr == MAP_FAILED)
    throw std::runtime_error("mmap error");
}

ShareMem::~ShareMem() {
  munmap(memaddr, len);
  shm_unlink(memname.c_str());
  sem_close(sem);
  sem_unlink(semname.c_str());
}

void ShareMem::operator=(const ImageType &data) {
  if (sem_wait(sem))
    throw std::runtime_error("Can't sem lock");
  memcpy(memaddr, &(data.frameID), sizeof(int64_t));
  memcpy(memaddr + sizeof(int64_t), data.data, data.size);
  if (sem_post(sem))
    throw std::runtime_error("Can't sem unlock");
}

std::pair<std::string, std::string> ShareMem::GetName() {
  return {memname, semname};
}
